<template>
  <div ref="container" class="markdown-container" v-html="renderedHtml"></div>
</template>

<script lang="ts" setup>
import { ref, onMounted, watch, nextTick } from 'vue'
import MarkdownIt from 'markdown-it'
import mermaid from 'mermaid'
import hljs from 'highlight.js'
import 'highlight.js/styles/github.css'

// --------------------------
// Props
// --------------------------
interface Props {
  markdown: string
}
const props = defineProps<Props>()

// --------------------------
// Refs
// --------------------------
const container = ref<HTMLDivElement | null>(null)
const renderedHtml = ref<string>('')

// --------------------------
// 初始化 Markdown-it + 高亮
// --------------------------
const md: MarkdownIt = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight: function (str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return `<pre class="hljs"><code>${hljs.highlight(str, { language: lang, ignoreIllegals: true }).value}</code></pre>`
      } catch (err) {
        console.error(err)
      }
    }
    return `<pre class="hljs"><code>${md.utils.escapeHtml(str)}</code></pre>`
  },
})

// --------------------------
// 自定义 fence 渲染器，支持 ```mermaid ``` 并安全转义
// --------------------------
const defaultFence = md.renderer.rules.fence?.bind(md.renderer.rules)

md.renderer.rules.fence = (tokens, idx, options, env, self) => {
  const token = tokens[idx]
  if (token.info.trim() === 'mermaid') {
    // 转义特殊字符，避免 Parse error
    const code = token.content
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
    return `<div data-mermaid="${code}"></div>`
  }
  return defaultFence?.(tokens, idx, options, env, self) || ''
}

// --------------------------
// Mermaid 初始化
// --------------------------
mermaid.initialize({
  startOnLoad: false,
  theme: 'base',
  themeVariables: {
    primaryColor: '#ffffff',
    primaryTextColor: '#111111',
    primaryBorderColor: '#E5E7EB',
    primaryBorderRadius: 8,
    secondaryColor: '#F9FAFB',
    tertiaryColor: '#F3F4F6',
    lineColor: '#9CA3AF',
    arrowheadColor: '#6B7280',
    clusterBkg: '#F9FAFB',
    clusterBorder: '#D1D5DB',
    noteBkgColor: '#F3F4F6',
    noteTextColor: '#111827',
    noteBorderColor: '#E5E7EB',
    fontFamily: 'Inter, Roboto, Helvetica, Arial, sans-serif',
    fontSize: '14px',
    fontWeight: '500',
  },
})

// --------------------------
// 渲染 Markdown
// --------------------------
const renderMarkdown = () => {
  renderedHtml.value = md.render(props.markdown)
}

// --------------------------
// 渲染 Mermaid
// --------------------------
const renderedMermaids = new WeakSet<HTMLElement>()

const renderMermaids = async () => {
  if (!container.value) return
  const mermaidElements = container.value.querySelectorAll<HTMLElement>('div[data-mermaid]')
  for (const el of mermaidElements) {
    if (renderedMermaids.has(el)) continue
    const code = el.dataset.mermaid || ''
    try {
      mermaid.parse(code)
      const id = `mermaid-${Math.random().toString(36).slice(2)}`
      const { svg } = await mermaid.render(id, code)
      el.innerHTML = svg
      renderedMermaids.add(el)
    } catch (e) {
      el.innerHTML = `<pre style="color:red">${(e as Error).message}</pre>`
    }
  }
}

// --------------------------
// 生命周期
// --------------------------
const updateMarkdown = async () => {
  renderMarkdown()
  await nextTick()
  await renderMermaids()
}

onMounted(updateMarkdown)

watch(
  () => props.markdown,
  updateMarkdown
)
</script>

<style scoped>
.markdown-container {
  width: 100%;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  line-height: 1.6;
}

/* 高亮样式 */
:deep(.hljs) {
  background: #f6f8fa;
  padding: 12px;
  border-radius: 8px;
  overflow-x: auto;
  font-size: 14px;
}

/* Mermaid 样式 */
:deep(.mermaid svg) {
  max-width: 100%;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: 14px;
  background-color: #f9f9f9;
  border-radius: 8px;
  padding: 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
</style>
